/************************************************************************************************************************
 ****************************************************** popups.js *******************************************************
 ************************************************************************************************************************/
/**
 * Created on : 2015/11/16
 * Author     : @kankan
 */

// create xpopup object
var xpopup = xpopup || {};

(function() {
    
    /**************************************************
     * Base prototype for all xpopupes and window
     **************************************************/
    var XPopupBase = function(options) {
		var self = this;
		
		self.$options = options;						// 加了$只是为了区分Js变量而已，可以用来表示这个变量是一个jquery对象，没其他含义
		self.$elem = null;

		self._init();
    };
    
    XPopupBase.prototype = {
        /******************* 私有方法 *******************/
        /* 初始化 */
        _init: function() {
            var self = this;

            self._preProcess();
            self._createDomElem();
            if (self.$options.draggable && !self._isMobileScreen()) {
                self.$elem.find('.xpopup').addClass('draggable');
                self._enableDrag();
            }
            if (self.$options.closeOnEsc) {
            	self._enableEsc();
            }
            if (self.$options.closeOnClkBg) {
            	self._enableClkBg();
            }
            self.setTitle(self.$options.title);
            self.setContent(self.$options.content);			// 制作load功能时，可以考虑在window里在执行setContent方法，或者参考原系统+++            
            self.show();
        },
        
        /* 预处理 */
        _preProcess: function() {
            var self = this;
            
            self.$options = $.extend({}, XPopupBase.DEFAULTS, self.$options);		// 将调用者的参数与本对象的默认参数进行合并
            for (var i in self.$options.buttons) {									// 对定义的按钮进行处理
                var btn = self.$options.buttons[i];

                if (self.$options.buttons.hasOwnProperty(i)) {						// 需要???
                	btn['class'] = btn['class'] ? btn['class'] : self.$options.btnDefaultClass;
                }
                self.$options.buttons[i] = btn;
            }
        },
        
        /* 构建HTML */
        _createDomElem: function() {
            var self = this;
            var xpopupWrapper = $('<div class="xpopup-wrapper"></div>');
            var xpopup = $('<div class="xpopup"></div>');
            var header = $('<div class="xpopup-header"></div>').append('<span class="xpopup-title"></span>').append(self._createTitleButtons());
            var body = $('<div class="xpopup-body"></div>');

            xpopup.append(header);
            xpopup.append(body);
            if (self.$options.buttons && !$.isEmptyObject(self.$options.buttons)) {
                var footer = $('<div class="xpopup-footer"></div>');
                footer.append(self._createCustomButtons());												// CALL  _createCustomButtons: function() {...
                if (XPopupBase.OPTIONS.buttonsAlign.indexOf(self.$options.buttonsAlign) > -1) {
                    footer.addClass('text-' + self.$options.buttonsAlign);
                }
                xpopup.append(footer);
            }
            xpopupWrapper.append(xpopup);
            
            xpopup.addClass(XPopupBase.OPTIONS.elemClass[self.$options.type]);
            if (self.$options.baseClass) {
                xpopup.addClass(self.$options.baseClass);
            }            
            if (self.$options.showClass) {
                xpopup.removeClass(self.$options.hideClass).addClass(self.$options.showClass);
            }
            
            xpopupWrapper.addClass(self.$options.maskClass);
            xpopupWrapper.addClass(self.$options.baseClass);
            xpopupWrapper.addClass('mask-animation-in');

            self.$elem = xpopupWrapper;
        },
        
        _createTitleButtons: function() {
            var self = this;
            var titleButtons = $('<div class="xpopup-header-tools"></span>');						// +++

            if (self.$options.btnMax) {
                titleButtons.append(self._createBtnMax());
            }
            if (self.$options.btnClose) {
                titleButtons.append(self._createBtnClose());
            }

			return titleButtons;
        },
        
        _createBtnMax: function() {
            var self = this;
            var max = true;
            var btnMax = $('<i class="btn-xpopup-header-tools"></i>').addClass(self.$options.btnMaxClass);
    		var curPosition;
    		var curWidht, curHeight;

    		btnMax.off('mousedown.xpopup').on('mousedown.xpopup', function(ev) {
                ev.stopPropagation();										// 阻止当前事件在DOM树上冒泡
            });
    		btnMax.off('click.xpopup').on('click.xpopup', function (ev) {
            	if (max) {
            		curWidht = self.$elem.find('.xpopup').width();
            		curHeight = self.$elem.find('.xpopup').height();
            		curPosition = self.$elem.find('.xpopup').position();
            		
                	self._setSize($(window).outerWidth(), $(window).outerHeight());
                	self.$elem.find('.xpopup').css({left: 0, top: 0});
                	btnMax.removeClass(self.$options.btnMaxClass).addClass(self.$options.btnRevertClass);
                	max = false;
                } else {
                	self._setSize(curWidht, curHeight);
                	self.$elem.find('.xpopup').css(curPosition);
                	btnMax.removeClass(self.$options.btnRevertClass).addClass(self.$options.btnMaxClass);
                	max = true;
                }
            });

			return btnMax;
        },
        
        _createBtnClose: function() {
            var self = this;
            var btnClose = $('<i class="btn-xpopup-header-tools btn-x"></i>').addClass(self.$options.btnCloseClass);
            
            btnClose.off('mousedown.xpopup').on('mousedown.xpopup', function(ev) {
                ev.stopPropagation();										// 阻止当前事件在DOM树上冒泡
            });
            btnClose.off('click.xpopup').on('click.xpopup', function (ev) {
                self.destroy();
            });

			return btnClose;
        },
        
        _createCustomButtons: function() {
            var self = this;
            var buttons = [];

            for (var i in self.$options.buttons) {
                var buttonOptions = self.$options.buttons[i];
                var button = self._createCustomButton(buttonOptions);		// CALL _createCustomButton: function(type, op) {...
                buttons.push(button);
            }
            
            return buttons;
        },

        _createCustomButton: function(buttonOptions) {
            var self = this;
            var button = $('<button type="button"></button>')
                    .addClass(buttonOptions['class'])
                    .attr('id', buttonOptions.id)
                    .html(buttonOptions.text);

            if (buttonOptions.handler && typeof buttonOptions.handler === 'function') {
            	button.off('mousedown.xpopup').on('mousedown.xpopup', function(ev) {
                    ev.stopPropagation();										// 阻止当前事件在DOM树上冒泡
                });
            	button.off('click.xpopup').on('click.xpopup', function(ev) {
                    buttonOptions.handler(self);
                });
            }
            
            return button;
        },

        /* 判断是否是移动设备屏幕 根据设备屏幕尺寸 */
        _isMobileScreen: function() {
        	return $(window).outerWidth() < 768 ? true : false;
        },
        
        /* 使能Drag */
        _enableDrag: function() {
        	var elem = this.$elem.find('.xpopup');
            var heading = elem.find('.xpopup-header');
            
            heading.off('mousedown.xpopup').on('mousedown.xpopup', function (ev) {
            	elem.attr('offset-left', ev.offsetX);
            	elem.attr('offset-top', ev.offsetY);
            	elem.attr('allow-drag', 'true');
            });
            $(document).off('mousedown.xpopup').on('mouseup.xpopup', function (ev) {
            	elem.attr('allow-drag', 'false');
            });
            $(document).off('mousemove.xpopup').on('mousemove.xpopup', function (ev) {
                if (elem.attr('allow-drag') === 'true') {
                    var left = ev.clientX - parseInt(elem.attr('offset-left'), 10) - parseInt(elem.css('border-left-width'), 10);
                    var top = ev.clientY - parseInt(elem.attr('offset-top'), 10) - parseInt(elem.css('border-top-width'), 10);
                    elem.css({
                        left: left,
                        top: top
                    });
                }
            });
        },

        /* 使能Esc */
        _enableEsc: function() {
            var self = this;
            
        	$(document).off('keyup.xpopup').on('keyup.xpopup', function(ev) {
	            if (ev.which === 27) {
	                self.destroy();
	            }
        	});
        },

        /* 使能ClkBg */
        _enableClkBg: function() {
            var self = this;
            
            self.$elem.off('click').on('click', function(event) {		// 点击popup本身也响应，需要改进+++
            	var event = event.target;
                if (event == this) {
                	self.destroy();
                }
        	});
        },
        
        /* 执行方法 */
        _execFunc: function(type) {
            var self = this;
            
            if (self.$options[type] && typeof self.$options[type] === 'function') {
                self.$options[type](self);
            }
        },
        
        /* Set the width of elem */
        _setWidth: function (width) {
            var self = this;
            
        	self.$elem.find('.xpopup').css('width', Math.min($(window).outerWidth(), width));
		},
        
        /* Set the height of elem and the xpopup-body */
        _setHeight: function (height) {
            var self = this;
			
			self.$elem.find('.xpopup').css('height', Math.min($(window).outerHeight(), height));
            self.$elem.find('.xpopup-body').css('height', self._getXPopupBodyHeight(height));
        },
        
        /* get the xpopup-body height */
        _getXPopupBodyHeight: function(height) {
            var self = this;
            
            var headerHeight = self.$elem.find('.xpopup-header').outerHeight();
            var footerHeight = self.$elem.find('.xpopup-footer').outerHeight();
            
            return height - (headerHeight ? headerHeight : 0) - (footerHeight ? footerHeight : 0) - (parseInt(self.$elem.find('.xpopup').css('border-top-width')) || 0) * 2;
        },

        /* 设置大小 */
        _setSize: function(width, height) {
            var self = this;

			self._setWidth(width);
			self._setHeight(height === 'auto' ? self.$elem.find('.xpopup').outerHeight() : height);
//			self._setHeight(500);
        },
        
        /* 获取对象居中时左上角点的坐标 */
        _getInitOffset: function() {
            var self = this;
            
            var left = ($(window).outerWidth() - self.$elem.find('.xpopup').outerWidth()) / 2;
            var top = ($(window).outerHeight() - self.$elem.find('.xpopup').outerHeight()) / 2;
            
            return {
                left: left,
                top: top
            };
        },

        /******************* 公共方法 *******************/
        /* Set the title of elem */
        setTitle: function (title) {
            var self = this;
            self.$elem.find('.xpopup-title').html(title);
        },
        
        /* 设置内容 */
		setContent: function (msg) {
			var self = this;
			self.$elem.find('.xpopup-body').html(msg);
        },
        
        /* Set the width of elem */
        setWidth: function (width) {
        	var self = this;
            self._setWidth(width);
            self.$elem.find('.xpopup').css('width', ($(window).outerWidth() - self.$elem.find('.xpopup').outerWidth()) / 2);
		},
        
        /* Set the height of elem and the xpopup-body */
        setHeight: function (height) {
        	var self = this;
            self._setHeight(height);
            self.$elem.find('.xpopup').css('top', ($(window).outerHeight() - self.$elem.find('.xpopup').outerHeight()) / 2);
        },
        
        /* Show self */
        show: function() {
            var self = this;

            self._execFunc('beforeShow');
            $('body').append(self.$elem);
            self._execFunc('afterShow');

            self._setSize(self.$options.width, self.$options.height);		// +++ header footer 高度无法能提前指定，_setSize就放在这里了
            self.$elem.find('.xpopup').css(self._getInitOffset());
        },
        
        /* Destroy */
        destroy: function() {
            var self = this;

            self._execFunc('beforeClose');
            self.$elem.removeClass('mask-animation-in');
            self.$elem.addClass('mask-animation-out');
            self.$elem.find('.xpopup').removeClass(self.$options.showClass);
            self.$elem.find('.xpopup').addClass(self.$options.hideClass);
            setTimeout(function() {
            	self.$elem.remove();
                self.$elem.find('.xpopup').remove();
                self._execFunc('afterClose');
            }, self.$options.delayToRemove);
            
            return this;
        }
	};

    /** XPopupBase用到的参数可选项对象  */
	XPopupBase.OPTIONS = {
        elemClass : {
    		'error'     : 'xpopup-error',
    		'success'   : 'xpopup-success',
    		'info'      : 'xpopup-info',
    		'warning'   : 'xpopup-warning',
    		'confirm'   : 'xpopup-confirm',
    		'progress'  : 'xpopup-progress',
    		'prompt'    : 'xpopup-prompt',
    		'default'   : 'xpopup-default',
    		'window'    : 'xpopup-window'
        },
        buttonsAlign: ['left', 'center', 'right']
    };

    /** XPopupBase用到的默认的参数对象 */
    XPopupBase.DEFAULTS = {
        width           : 600,
        height          : 'auto',									// Height is automatically given getd by width

        title			: 'Title',
        btnMax       	: false,
        btnMaxClass		: 'btn-max fa fa-circle',
        btnRevertClass	: 'btn-revert fa fa-circle',
        btnClose       	: true,
        btnCloseClass	: 'fa fa-circle',
        btnDefaultClass : 'btn btn-default',						// Default class for custom buttons		OR BootStrap Style: btn btn-default
        maskClass		: 'with-mask-default',
        baseClass       : 'animated-fast',							// animated-super-fast, animated-fast, animated, animated-slow
        showClass       : 'zoomIn',
        hideClass       : 'zoomOut',
        
        draggable       : true,										// Make xpopup draggable
        buttonsAlign    : 'right',									// Position where buttons should be aligned
        closeOnEsc      : false,									// Close xpopup on Esc press
        closeOnClkBg	: false,									// Close xpopup on Click Background
        delayToRemove   : 300,
        
        // events
        beforeShow      : null,
        afterShow       : null,
        beforeClose     : null,
        afterClose		: null
    };

    
    /**************************************************
     * XPopupAlert
     **************************************************/
    function XPopupAlert(options) {
		var self = this;
        this.$options	= options;
		
		self._extInit();
    };

    XPopupAlert.prototype = $.extend({}, XPopupBase.prototype, {
        /* 扩展初始化 */
    	_extInit: function() {
            var self = this;
			
            self.$options = $.extend({}, XPopupAlert.OPTIONS[self.$options.type], XPopupAlert.DEFAULTS, self.$options);
            self._setContent();
            self._init();		// 调用基类中的初始化方法
            return self;		// VERY IMPORTANT!!! 这样才能继续调用后面的其它方法
        },
        
        /* 设置内容 */
    	_setContent: function() {
            var self = this;
            
            var d = $('<div></div>');
            if (self.$options.iconClass) {
                d.append($('<div class="xpopup-body-icon-wrapper"></div>').append('<i class="xpopup-icon ' + self.$options.iconClass + '"></i>'));
            }
            d.append('<div class="xpopup-body-text-wrapper"><span class="xpopup-body-text">' + self.$options.msg + '</span></div>');
            self.$options.content = d.html();
        }
    });

    XPopupAlert.OPTIONS = {
        warning: {
            title: 'Warning',
            iconClass: 'glyphicon glyphicon-exclamation-sign'
        },
        info: {
            title: 'Information',
            iconClass: 'glyphicon glyphicon-info-sign'
        },
        success: {
            title: 'Success',
            iconClass: 'glyphicon glyphicon-ok-sign'
        },
        error: {
            title: 'Error',
            iconClass: 'glyphicon glyphicon-minus-sign'
        }
    };
    
    XPopupAlert.DEFAULTS = {
    	type			: 'success',
       	closeOnEsc      : true,										// Close xpopup on Esc press
        closeOnClkBg	: true,										// Close xpopup on Click Background
    };

    
    /**************************************************
     * XPopupConfirm
     **************************************************/
    function XPopupConfirm(options) {
		var self = this;
        this.$options	= options;
		
		self._extInit();
    };

    XPopupConfirm.prototype = $.extend({}, XPopupBase.prototype, {
    	/* 扩展初始化 */
    	_extInit: function() {
            var self = this;
            
            self.$options = $.extend({}, XPopupConfirm.DEFAULTS, self.$options);
            self._setContent();
			self._init();		// 调用基类中的初始化方法
            return self;		// VERY IMPORTANT!!! 这样才能继续调用后面的其它方法
        },
        
        /* 设置内容 */
    	_setContent: function() {
            var self = this;
            
            var d = $('<div></div>');
			if (self.$options.iconClass) {
			    d.append($('<div class="xpopup-body-icon-wrapper"></div>')
			        .append('<i class="xpopup-icon ' + self.$options.iconClass + '"></i>'));
			}
            d.append('<div class="xpopup-body-text-wrapper"><span class="xpopup-body-text">' + self.$options.msg + '</span></div>');
            self.$options.content = d.html();
        }
    });
    
    XPopupConfirm.DEFAULTS = {
    	type			: 'confirm',
        title           : 'Question',
        iconClass       : 'glyphicon glyphicon-question-sign',
        closeOnEsc      : true,										// Close xpopup on Esc press
        closeOnClkBg	: true,										// Close xpopup on Click Background
    };
    

    /**************************************************
     * XPopupProgress
     **************************************************/
    function XPopupProgress(options) {
		var self = this;
		
		self.$options = options;
		self.$progressBarElement = null,
		self.$progress = 0;

		self._extInit();
    };

	XPopupProgress.prototype = $.extend({}, XPopupBase.prototype, {
        /* 扩展初始化 */
    	_extInit: function() {
            var self = this;

            self.$options = $.extend({}, XPopupProgress.DEFAULTS, self.$options);
            self._setContent();
            self._init();		// 调用基类中的初始化方法
            return self;		// VERY IMPORTANT!!! 这样才能继续调用后面的其它方法
        },
        
        /* 设置内容 */
    	_setContent: function() {
            var self = this;
            
            if (self.$options.progressTpl) {
                self.$progressBarElement = $(self.$options.progressTpl);
            } else {
                self.$progressBarElement = self._createProgressbar();
            }
            var label;
            if (self.$options.label) {
                label = $('<label>' + self.$options.label + '</label>');
            }
            var d = $('<div></div>').append(label, self.$progressBarElement);
            self.$options.content = d.html();
        },
        
        _createProgressbar: function() {
            var self = this;

            var outer = $('<div class="xpopup-progress-bar-wrapper xpopup-progress-outer"></div>');
            if (self.$options.showProgressLabel) {
                outer.append('<span class="xpopup-progress-text" data-role="progress-text"></span>');
            }
            outer.append('<div class="xpopup-progress-bar progress-bar progress-bar-success progress-bar-striped active"></div>');	/* +k: use bootstrap progress */
           
            return outer;
        },
        
        /* Set progress value */
        setProgress: function(progress) {
            var self = this;

            if (self.$progress === 100) {
                return;
            }
            progress = Math.min(100, Math.max(0, progress));
            self.$progress = progress;
            self._execFunc('progressUpdated');
            if (self.$progress === 100) {
                self._execFunc('progressCompleted');
            }
            self.$elem.find('.xpopup-progress-bar').css('width', progress.toFixed(1) + "%");
            self.$elem.find('[data-role="progress-text"]').html(progress.toFixed(1) + "%");
        },
        
        /* Get progress value */
        getProgress: function() {
            return this.$progress;
        }
	});
    
    XPopupProgress.DEFAULTS = {
       	type				: 'progress',
       	closeOnEsc      	: true,					// Close xpopup on Esc press
        closeOnClkBg		: true,					// Close xpopup on Click Background
        showProgressLabel   : true,  				// Show percentage of progress
        label               : '',  					// Show progress label
        progressTpl         : false,				// Template of progress bar
        
        // Events
        progressUpdated     : null,
        progressCompleted   : null
    };
    

    /**************************************************
     * XPopupWindow
     **************************************************/
    function XPopupWindow(options) {
		var self = this;
		
		self.$options = options;
		self._extInit();
    };

    XPopupWindow.prototype = $.extend({}, XPopupBase.prototype, {
        /* 扩展初始化 */
    	_extInit: function() {
            var self = this;
            
	        self.$options = $.extend({}, XPopupWindow.DEFAULTS, self.$options);
            self._init();		// 调用基类中的初始化方法
            return self;		// VERY IMPORTANT!!! 这样才能继续调用后面的其它方法
        },
    });

    XPopupWindow.DEFAULTS = {
   		type			: 'window',
   		title			: 'Window',
        btnMax       	: false,
        content         : '',					// HTML Content of window
        href			: '',					// href which will be used to load PAGE :k+
    };

    /** xpopup */
    xpopup.defaults = XPopupBase.DEFAULTS;
    
	xpopup.alert = function (options) {
    	return new XPopupAlert(options);
    };
    xpopup.alert.defaults = XPopupAlert.DEFAULTS;

    xpopup.confirm = function (options) {
    	return new XPopupConfirm(options);
    };
    xpopup.confirm.defaults = XPopupConfirm.DEFAULTS;

    xpopup.progress = function (options) {
    	return new XPopupProgress(options);
    };
    xpopup.progress.defaults = XPopupProgress.DEFAULTS;

    xpopup.window = function (options) {
    	return new XPopupWindow(options);
    };
    xpopup.window.defaults = XPopupWindow.DEFAULTS;
    
})();




/************************************************************************************************************************
 ****************************************************** xloading.js ******************************************************
 ************************************************************************************************************************/
/**
 * Created on : 2016/01/26
 * Author     : @kankan
 */

// create xpopup object
var xpopup = xpopup || {};

(function() {
	
    /**************************************************
     * XPopupLoading
     **************************************************/
	function XPopupLoading(options) {
		var self = this;
		
		self.$options = options;						// 加了$只是为了区分Js变量而已，可以用来表示这个变量是一个jquery对象，没其他含义
		self.$elem = null;

		self._init();
	};

	XPopupLoading.prototype = {
		_init: function() {
	        var self = this;

	        self.$options = $.extend({}, XPopupLoading.DEFAULTS, self.$options);
            self._createDomElem();
            self.show();
			
	        return self;								// VERY IMPORTANT!!! 这样才能继续调用后面的其它方法
	    },

        /* 构建HTML */
        _createDomElem: function() {
            var self = this;

			var lw = $('<div class="xloading ' + self.$options.maskClass + '"></div>');
			var core = $(XPopupLoading.OPTIONS.elemStyle[self.$options.style]);
    	    if (self.$options.content) {
    	    	core.append('<span class="pacman-txt">' + self.$options.content + '</span>');
    	    }
			lw.append(core);
            self.$elem = lw;
        },
        
        /* Show self */
        show: function() {
            var self = this;
            $('body').append(self.$elem);
        },
        
        /* Destroy */
        destroy: function() {
            var self = this;
            $('.xloading').remove();
            return this;
        }
	};
	
	XPopupLoading.OPTIONS = {
        elemStyle : {
    		'pacman'	: '<div class="x-pacman-wrap">\
						      	<div class="pacman">\
									<div></div>\
									<div></div>\
									<div></div>\
									<div></div>\
									<div></div>\
								</div>\
							</div>',
    		'square'	: '<div class="x-pacman-wrap spinner-wrap"><div class="spinner"></div></div>'
        }
    };
	
	XPopupLoading.DEFAULTS = {
	   	style			: 'pacman',
	   	maskClass		: 'with-mask-transparent',
        content			: '',
	};
	
	/* xpop.loading */
    xpopup.loading = function (options) {
    	return new XPopupLoading(options);
    };
    xpopup.loading.defaults = XPopupLoading.DEFAULTS;
    
})();




/************************************************************************************************************************
 ************************************************ xnotify.js ******************************************************
 ************************************************************************************************************************/
/**
 * Created on : 2017/03/28
 * Author     : @kankan
 */

// create xpopup object
var xpopup = xpopup || {};

(function() {
    
    /**************************************************
     * XPopupNotify
     **************************************************/
    var XPopupNotify = function(options) {
		var self = this;
		
		self.$options = options;						// 加了$只是为了区分Js变量而已，可以用来表示这个变量是一个jquery对象，没其他含义
		self.$elem = null;

		self._init();
    };
    
    XPopupNotify.prototype = {
        /******************* 私有方法 *******************/
        /* 初始化 */
    	_init: function() {
        	var self = this;

        	self.$options = $.extend({}, XPopupNotify.DEFAULTS, self.$options);
            
            if (self.$options.icon) {
            	self.$options.icon = XPopupNotify.OPTIONS[self.$options.type].icon;
            }
            if (self.$options.sound) {
            	self.$options.sound = self.$options.soundPath + XPopupNotify.OPTIONS[self.$options.type].sound + self.$options.soundExt;
            }

            self._createDomElem();
            
            self.show();
            self.play();
        },
        
        _createDomElem: function() {
        	var self = this;
        	
            ////// core
            var selector = '';
            if (self.$options.style !== 'square') {
                var classes = self.$options.position.split(" ");
                selector += "." + classes.join('.');
            }
            
            var notify = $('<div class="xpopup-notify"></div>')
		            .addClass(XPopupNotify.OPTIONS[self.$options.style]['class'])
		            .addClass(XPopupNotify.OPTIONS[self.$options.type]['class'])
    				.addClass(selector.replace(/\./g, ' ').trim())
                    .addClass(self.$options.baseClass)
                    .addClass(self.$options.showClass);

            // Add image or icon depending on given parameters  
            var iconWrapper = $('<div class="xpopup-notify-icon"></div>').appendTo(notify);		// Create icon wrapper class
            if (self.$options.img) {
                var img = iconWrapper.append('<img src="' + self.$options.img + '" />');
                iconWrapper.append(img);
            } else if (self.$options.icon) {
                var icon = iconWrapper.append('<i class="' + self.$options.icon + '"></i>');
                iconWrapper.append(icon);
            } else {
                notify.addClass('without-icon');
            }
            
            // Create body, append title and selfssage in body and append body in notification
            var notifyBody = $('<div class="xpopup-notify-body"></div>')
                    .append('<div class="xpopup-notify-msg">' + self.$options.msg + '</div>')
                    .appendTo(notify);
            if (self.$options.style !== 'mini') {
            	notifyBody.prepend('<div class="xpopup-notify-title">' + self.$options.title + '<div>');
            }
            
            if (self.$options.btnClose && self.$options.style !== 'square') {
                self._addBtnClose(notify);
            }
        	self._addCloseOnClick(notify);
        	self._addDelay(notify);
            
            // Give width to notification
            if (self.$options.width) {
                notify.css('width', self._getWidth(self.$options.width));
            }
            
            self.$elem = notify;
        },

        _addBtnClose: function($elem) {
        	var self = this;
        	
            if (!self.$options.closable) {
                return;
            }
            var close = $('<span class="xpopup-close"><i class="' + self.$options.btnCloseClass + '"></i></span>');
            $elem.append(close);
            close.click(function(ev) {
                ev.stopPropagation();										// 阻止当前事件在DOM树上冒泡
                self.destroy();
            });
        },
        
        _addCloseOnClick: function($elem) {
        	var self = this;
        	
            if (!self.$options.closeOnClick) {
                return;
            }
            $elem.click(function() {
                self.destroy();
            });
        },
        
        _addDelay: function($elem) {
        	var self = this;
        	
            if (!self.$options.delay) {
                return;
            }
            
            if (self.$options.delayIndicator) {
                var delay = $('<div class="xpopup-delay-indicator"><div></div></div>');
                $elem.append(delay);
            }
            
            var time = 0;
            var interval = 1000/30;
            var timer = setInterval(function() {
                time += interval;
                var width = 100 * time / self.$options.delay;
                if (width >= 100) {
                    width = 100;
                    self.destroy();
                    timer = clearInterval(timer);
                }
                if (self.$options.delayIndicator) {
                    delay.find('div').css('width', width + "%");
                }
            }, interval);
        },
        
        _getWidth: function(width) {
            width = Math.min($(window).outerWidth(), width);
            return width;
        },
        
        /* Show self */
        show: function() {
            var self = this;
            $('body').append(self.$elem);
        },
        
        /* Play sound */
        play: function() {
            var self = this;

            if (self.$options.sound) {
                var snd = new Audio(self.$options.sound); // buffers automatically when created
                snd.play();
            }
        },
        
        /* Destroy */
        destroy: function() {
        	var self = this;
        	
            self.$elem.removeClass(self.$options.showClass).addClass(self.$options.hideClass);
            setTimeout(function() {
            	self.$elem.remove();

                if (self.$options.afterClose && typeof self.$options.afterClose === 'function') {
                    self.$options.afterClose(self);
                }
            }, 500);
            
            return self;
        }
    };
    
    // This variable is necessary.
    XPopupNotify.OPTIONS = {
        normal: {
            'class': 'notify-normal'
        },
        mini: {
            'class': 'notify-mini'
        },
        square: {
            'class': 'notify-square'
        },
        success: {
            'class': 'xpopup-notify-success',
            'title': 'Success',
            'icon': 'glyphicon glyphicon-ok-sign',
            sound: 'sound2'
        },
        error: {
            'class': 'xpopup-notify-error',
            'title': 'Error',
            'icon': 'glyphicon glyphicon-minus-sign',
            sound: 'sound4'
        },
        warning: {
            'class': 'xpopup-notify-warning',
            'title': 'Warning',
            'icon': 'glyphicon glyphicon-exclamation-sign',
            sound: 'sound5'
        },
        info: {
            'class': 'xpopup-notify-info',
            'title': 'Information',
            'icon': 'glyphicon glyphicon-info-sign',
            sound: 'sound6'
        }
    };
    
    // User can set default options to this variable
    XPopupNotify.DEFAULTS = {
        width: 0,                 					// Width of notification box
        
    	style: 'normal',             				// normal, mini, square
    	type: 'success',							// type...
        title: '',	                				// Title of notification. If you do not include the title in options it will automatically takes its value
        msg: '',                    				// Message of notification
        icon: true,                 				// Icon of notification. Leave as is for default icon or set custom string
        img: null,                  				// Image source string
        btnClose		: true,
        btnCloseClass	: 'glyphicon glyphicon-remove',
        baseClass		: 'animated-fast',
        showClass		: 'zoomIn',        			// Show animation class
        hideClass		: 'zoomOut',       			// Hide animation class
        
        closable: true,             				// Make notifications closable
        delay: 3000,                				// Hide notification after this time (in miliseconds)
        delayIndicator: true,       				// Show timer indicator
        closeOnClick: true,         				// Close notifications by clicking on them
        sound: false,                				// Sound of notification. Set this false to disable sound. Leave as is for default sound or set custom soud path
        position: "bottom right",    				// Place to show notification. Available options: "top left", "top right", "bottom left", "bottom right"

        soundPath: './static/plugins/xPopup/sounds/',   // The folder path where sounds are located
        soundExt: '.ogg',           				// Default extension for all sounds
        
        // events
        afterClose		: null,
    };
    
    /* xpopup.notify */
	xpopup.notify = function(options) {
        return new XPopupNotify(options);
    };
    xpopup.notify.defaults = XPopupNotify.DEFAULTS;
    
})();
